package org.sosie2.service.authorization;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.InvalidPropertiesFormatException;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;

import javax.xml.soap.SOAPMessage;

import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.opensaml.SAMLAttribute;
import org.opensaml.SAMLAttributeStatement;
import org.sosie2.service.framework.AbstractService;
import org.sosie2.service.framework.SAMLAnnotation;
import org.sosie2.service.framework.SosieException;
import org.sosie2.service.framework.Utils;
import org.w3c.dom.Document;


/**
 * 
 * A simple authorization using the SOAP Annotations. 
 * The service receives a soap message, looks for a specific tag 
 * (authenticatedUser) to see if the user is already authenticated; 
 * then it checks the userName against a list it instantiates during the init stage. 
 * if the userName is present, then the user is considered to be authorized from now on.
 * 
 * @author Gabriela
 */
public class SimpleAuthorizationService extends AbstractService {
	
	static Logger logger = Logger.getLogger(SimpleAuthorizationService.class);
	
	public static final String ACTOR = Utils.ACTOR;
	
	public static final String AUTHOR = Utils.AUTHO_AUTHOR;
	
	public String userName;
	
	private Properties authorizationList = new Properties();
	
	protected Properties config = new Properties();
	
	/**
	 * A simple constructor that calls init()
	 */
	public SimpleAuthorizationService() {
		init();
	}
	
	/**
	 * initialization of logger and loading the fle with the authorization names
	 */ 
	public void init() {
		Utils instanceUtils = Utils.get();
		URL url = instanceUtils.getFile("configuration//" + Utils.LOGGER_FILE);
		if (url == null)
			System.out.println("URL NULL for logger file" );
		else {	
			PropertyConfigurator.configure(url);
		}
		
		String authorizationFile = config.getProperty("authorizationFile");
		try {
			authorizationList = this.loadProperties(authorizationFile);
		} catch(Exception e) {
			logger.fatal("SimpleAuthorization service: exception occured - " + e.getMessage());
			e.printStackTrace();
		}
	}
	

	public Message invoke(Message req, Message resp) throws Exception {				
		
		// extracting the userName of the user which is already authenticated
		// get all annotations in one list
		SAMLAnnotation[] annotations = getAllAnnotations(req.getSOAPEnvelope().getAsDocument());
		
		if (annotations.length == 0) {
			logger.info("SIMPLE AUTHORIZATION SERVICE......................");
			logger.warn("No annotations in the  message header ...");
			
			throw new SosieException("No annotations found");				
		}
		
		// iterate over the list in search for the "authenticatedUser" tag  
		for (int i=0; i<annotations.length; i++) {			
			Iterator it = annotations[i].getAttributeStatements().iterator();
			
			while (it.hasNext()) {
				SAMLAttributeStatement ss = (SAMLAttributeStatement)it.next();
				
				for(Iterator j = ss.getAttributes(); j.hasNext();) {
					SAMLAttribute attrib = (SAMLAttribute)j.next();
					
					if (attrib.getName().equals("authenticatedUser")) {
						this.userName = (String)attrib.getValues().next();
						break;
					}
				}
			}
		}
					
		// check the userName for access rights by checking it against the list			
		if (Boolean.parseBoolean(authorizationList.getProperty(this.userName,"false"))) {
			// Is authorized - do nothing
			logger.info("User <" + userName + "> is authorized");
			
			// removing annotation with the tag "authenticatedUser" here
    		Document doc = resp.getSOAPEnvelope().getAsDocument();
    		doc = deleteAnnotation(doc, "authenticatedUser");
    		
    		// adding annotation with the tag "authorizedUser"
    		String[][] att = new String[1][2];
    		att[0][0] = "authorizedUser";
    		att[0][1] = this.userName;
    		
    		//attach the hashmap + rest of parameters to the annotation
    		SAMLAnnotation sa = new SAMLAnnotation (att, ACTOR, "LDAPAuthentication");
    		doc = addAnnotation(doc, sa, AUTHOR);
    		    		        		
    		SOAPMessage soapMsg = Utils.toMessage(doc);
    		ByteArrayOutputStream out = new ByteArrayOutputStream();
    		soapMsg.writeTo(out);
    		
    		Message msg = new Message(new ByteArrayInputStream(out.toByteArray()), false);
    	    return msg;    	       	    
		} else { 
			// Not authorized - generate special exception
			logger.info("SIMPLE AUTHORIZATION SERVICE......................");
			throw new SosieException("User <" + userName + "> is NOT authorized");				
		}			
	}
	

	/**
	 * This function loads a configuration file into memory (a Properties object is used ).
	 * @param propertyFile
	 * @return a Properties object
	 * @throws FileNotFoundException
	 * @throws InvalidPropertiesFormatException
	 * @throws IOException
	 */
	protected Properties loadProperties(String propertyFile) 
		throws FileNotFoundException, InvalidPropertiesFormatException,IOException {

		Properties ret = new Properties();
		
		URL u = getClass().getClassLoader().getResource("config/" + propertyFile);
		
		try { 			
			ret.loadFromXML(u.openStream());			
		}  catch (Exception e) {			
			ret.load(u.openStream());			
		} 
		
		return ret;	
	}
	
}
